public class Maze {
	
	/* defined below are the basic attributes of the maze. None of these variables should be publicly
	 * accessible, as the maze data could be courrupted with external modification. Getter functions
	 * exist to use the values of these.
	 */
	private int width;
	private int height;
	
	private int start_x;
	private int start_y;
	
	private int exit_x;
	private int exit_y;
	
	private MazeTile[] data;

	/* The constructor for the Maze structure. This function takes two arguments, width and height, and
	 * returns a new Maze structure, containing a randomly generated maze. the width and height properties are
	 * set, the data is allocated, and the buildMaze internal function is called automatically.
	 */
	public Maze ( int w, int h ) {
		width = w;
		height = h;
		data = new MazeTile[ w * h ];
		
		//m_buildMaze();
	}
	
	/* Access functions for the internal private variables.*/
	public int getWidth () {
		return width;
	}
	
	public int getHeight () {
		return height;
	}
	
	public int getStartX () {
		return start_x;
	}
	
	public int getStartY () {
		return start_y;
	}

	public int getExitX () {
		return exit_x;
	}
	
	public int getExitY () {
		return exit_y;
	}
	
	public void setStart ( int x, int y ) {
		start_x = x;
		start_y = y;
	}
	
	public void setExit ( int x, int y ) {
		exit_x = x;
		exit_y = y;
	}
	
	/* GetTile returns the tile enumerator for the maze tile at coordinates X,Y.
	 * This function assumes that all coordinates outside of the maze area are defined as walls. 
	 * This is simply to ensure that the player does not leave the bounds of the game area.
	 */
	public MazeTile getTile ( int x, int y ) {
		if ( x < 0 || x > getWidth() || y < 0 || y > getHeight() )
			return MazeTile.WALL;
		return data[ m_index(x,y) ];
	}
	
	public void setTile ( int i, MazeTile val ) {
		data[ i ] = val;
	}
	
	public void setTile ( int x, int y, MazeTile val ) {
		data[ m_index(x,y) ] = val;
	}
	
	/* PrintMaze outputs the maze structure to Stdout, drawing it with ASCII characters. 
	 * The exit is marked with "EE", the start is marked with "SS", and walls are defined with "[]".
	 */
	public void printMaze () {
		for ( int x = 0; x < getWidth(); x ++ ) {
			String ln = "";
			for ( int y = 0; y < getHeight(); y ++ ) {
				if ( x == getExitX() && y == getExitY() ) {
					ln += "E";
				}else if( x == getStartX() && y == getStartY() ) {
					ln += "S";
				}else{
					switch ( getTile(x,y) ) {
						case PATH: 
							ln += " ";
							break;
						case WALL:
							ln += "X";
							break;
						default:
							ln += "U";
							break;
					}
				}
			}
			System.out.println( ln );
		}
	}

	
	/* The m_index function clamps a set of coordinates to a range between 0 and w/h.
	 * Then, it returns the index into a 2D array specified at y * width + x.
	 */
	private int m_index ( int x, int y, int w, int h ) {
		if ( x < 0 ) x = 0;
		if ( x >= w ) x = w-1;
		if ( y < 0 ) y = 0;
		if ( y >= h ) y = h-1;
		
		return y * w + x;
	}
	
	/* This variant of the m_index function only takes two arguements, omitting the width and height
	 * parameters, and assumes that the max width and height are the values returned by "getWidth", and
	 * "getHeight" respectively. Again, this implementation of m_index is just for convenience.
	 */
	private int m_index ( int x, int y ) {
		return m_index( x, y, getWidth(), getHeight() );
	}
	
}
